﻿#light

open Common.Monads.State


let combineList xs = 
 match xs with
  | [] -> state.Zero()
  | x::xs -> List.fold_right (fun s1 s2 -> state.Combine(s1,s2)) xs x


type Given<'state>        = | Given of (unit -> 'state)
type AndGiven<'state, 'a> = | AndGiven of Common.Monads.State<'state,'a> list * Given<'state>
type When<'state, 'a>     = | When of Common.Monads.State<'state,'a> * AndGiven<'state, 'a>
type Then<'state, 'a>     = | Then of Common.Monads.State<'state,'a> list * When<'state, 'a> 

let given str = AndGiven([], Given str)
let andGiven str (AndGiven (givenList,scenario)) = AndGiven (str :: givenList ,scenario)
let whens str given = When (str, given)
let thens str whens = Then ([str], whens)
let andThens str (Then (thenList,given)) = Then (str::thenList,given)

let endStoryWith strategy 
                 (Then (thenList, 
                   When (whenItem, 
                    (AndGiven (givenList, 
                      Given init))))) = strategy (combineList [combineList (List.rev givenList); whenItem; combineList (List.rev thenList)]) (init()) 

let endStory () = endStoryWith Exec

(*
let endStory (Then (thenList, 
                   When (whenItem, 
                    (AndGiven (givenList, 
                      Given init))))) = Exec (combineList [combineList (List.rev givenList); whenItem; combineList (List.rev thenList)]) (init())
*)
